001: /*
002: * ====================================================================
003: * JAFFA - Java Application Framework For All
004: *
005: * Copyright (C) 2002 JAFFA Development Group
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: * Redistribution and use of this software and associated documentation ("Software"),
022: * with or without modification, are permitted provided that the following conditions are met:
023: * 1. Redistributions of source code must retain copyright statements and notices.
024: * Redistributions must also contain a copy of this document.
025: * 2. Redistributions in binary form must reproduce the above copyright notice,
026: * this list of conditions and the following disclaimer in the documentation
027: * and/or other materials provided with the distribution.
028: * 3. The name "JAFFA" must not be used to endorse or promote products derived from
029: * this Software without prior written permission. For written permission,
030: * please contact mail to: jaffagroup@yahoo.com.
031: * 4. Products derived from this Software may not be called "JAFFA" nor may "JAFFA"
032: * appear in their names without prior written permission.
033: * 5. Due credit should be given to the JAFFA Project (http://jaffa.sourceforge.net).
034: *
035: * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: */
049: package org.jaffa.tools.patternmetaengine;
050:
051: import java.io.File;
052: import java.io.FileOutputStream;
053: import java.io.IOException;
054: import java.io.FileNotFoundException;
055: import java.util.List;
056: import java.util.Iterator;
057: import java.util.ArrayList;
058: import java.util.Properties;
059:
060: import javax.xml.bind.JAXBContext;
061: import javax.xml.bind.Validator;
062: import javax.xml.bind.ValidationException;
063: import javax.xml.bind.JAXBException;
064: import javax.xml.bind.Marshaller;
065: import javax.xml.bind.util.ValidationEventCollector;
066: import javax.xml.bind.ValidationEvent;
067:
068: import org.apache.log4j.Logger;
069: import org.jaffa.util.StringHelper;
070: import org.jaffa.datatypes.Defaults;
071: import org.jaffa.tools.patternmetaengine.domain.ApplicationBuilder;
072: import org.jaffa.tools.patternmetaengine.domain.Module;
073: import org.jaffa.patterns.library.domain_creator_1_1.domain.Root;
074: import org.jaffa.patterns.library.object_maintenance_meta_1_0.domain.*;
075: import org.jaffa.patterns.library.domain_creator_1_1.domain.RelationshipField;
076:
077: /** Build a simple maintenace component for a domain object.
078: * This will give the user the ability to create, update and delete this object.
079: * Its main access point for update and deleve will be via a related finder component.
080: *
081: * At this point the pattern does not support linking to related many entities for
082: * maintenace. Once the pattern evolves, this generator will be enhanced.
083: *
084: * @author PaulE
085: */
086: public class BuildObjectMaintenance_1 implements IBuilder {
087:
088: /** Set up Logging for Log4J */
089: private static Logger log = Logger
090: .getLogger(BuildObjectMaintenance.class);
091:
092: private ApplicationBuilder m_app = null;
093: private Module m_module = null;
094: private Root m_domain = null;
095: private DomainObjectHelper m_doList;
096:
097: private ObjectMaintenanceMeta m_maint = null;
098: private Properties m_labels = null;
099:
100: private ComponentRegistry m_compReg = null;
101:
102: /** Creates a new instance of BuildObjectMaintenance */
103: public BuildObjectMaintenance_1(
104: ApplicationBuilder app,
105: ComponentRegistry comps,
106: Module module,
107: org.jaffa.patterns.library.domain_creator_1_1.domain.Root domain,
108: DomainObjectHelper doList, Properties labels) {
109:
110: log.debug("Create Maintenance For - "
111: + domain.getDomainObject());
112: m_compReg = comps;
113: m_app = app;
114: m_module = module;
115: m_domain = domain;
116: m_labels = labels;
117: m_doList = doList;
118: }
119:
120: /** Causes the meta data object to be build ready for saving.
121: * @param fullPackage If true then the .applications. and .modules. package names
122: * are used. If this is false, these are ommited for a much more condensed package
123: * naming convention
124: */
125: public void buildPhase1(boolean fullPackage) throws Exception {
126: ObjectFactory objFactory = new ObjectFactory();
127: try {
128: m_maint = objFactory.createObjectMaintenanceMeta();
129: m_maint
130: .setPatternTemplate("patterns/library/object_maintenance_1_0/ObjectMaintenancePattern.xml"); // Mand
131: m_maint.setApplication(m_app.getApplicationName()); // Mand
132: m_maint.setModule(m_module.getName()); // Mand
133: m_maint.setComponent(m_domain.getDomainObject()
134: + "Maintenance"); // Mand
135: StringBuffer sb = new StringBuffer();
136: sb.append(m_app.getPackagePrefix());
137: sb.append(".");
138: if (fullPackage)
139: sb.append("applications.");
140: sb.append(m_app.getApplicationName());
141: sb.append(".");
142: if (fullPackage)
143: sb.append("modules.");
144: sb.append(m_module.getName());
145: m_maint.setBasePackage(sb.toString().toLowerCase()); // Mand
146: m_maint.setDomainObject(m_domain.getDomainObject()); // Mand
147: m_maint.setDomainPackage(m_domain.getDomainPackage()); // Mand
148:
149: // Create Labels for the screen titles
150: String labelDomain = "label."
151: + StringHelper
152: .getUpper1(m_app.getApplicationName())
153: + "."
154: + StringHelper.getUpper1(m_module.getName())
155: + "."
156: + StringHelper
157: .getUpper1(m_domain.getDomainObject());
158: String labelId = "title."
159: + StringHelper
160: .getUpper1(m_app.getApplicationName())
161: + "."
162: + StringHelper.getUpper1(m_module.getName())
163: + "."
164: + StringHelper
165: .getUpper1(m_domain.getDomainObject())
166: + "Maintenance.";
167: // Criteia Title
168: m_maint.setCreateTitle(labelId + "create"); // Opt
169: m_labels.put(m_maint.getCreateTitle(), "Create ["
170: + labelDomain + "]");
171: // Results Title
172: m_maint.setUpdateTitle(labelId + "update"); // Opt
173: m_labels.put(m_maint.getUpdateTitle(), "Update ["
174: + labelDomain + "]");
175:
176: //----------------------------------------------
177: // Before we list the fields, we need to remove any foriegn fields and make them
178: // part of a foriegn object
179:
180: //---------------------------
181: // Find foriegn objects that relate to this one
182: List upDomain = new ArrayList();
183: List upRel = new ArrayList();
184: for (Iterator it = m_doList.iterator(); it.hasNext();) {
185: org.jaffa.patterns.library.domain_creator_1_1.domain.Root domain = (org.jaffa.patterns.library.domain_creator_1_1.domain.Root) it
186: .next();
187: if (domain.getRelationships() != null) {
188: List rels = domain.getRelationships()
189: .getRelationship();
190: if (rels != null && !rels.isEmpty())
191: for (Iterator it2 = rels.iterator(); it2
192: .hasNext();) {
193: org.jaffa.patterns.library.domain_creator_1_1.domain.Relationship rel = (org.jaffa.patterns.library.domain_creator_1_1.domain.Relationship) it2
194: .next();
195: if (m_domain.getDomainObject().equals(
196: rel.getToDomainObject())
197: && m_domain
198: .getDomainPackage()
199: .equals(
200: rel
201: .getToDomainPackage())) {
202: // This domain object relates to this one
203: upDomain.add(domain);
204: upRel.add(rel);
205: break;
206: }
207: }
208: }
209: }
210:
211: //------------------------------------
212: // Loop through foriegn objects
213: List processedFields = new ArrayList();
214: if (upDomain.size() > 0) {
215: ForeignObjects fos = objFactory.createForeignObjects();
216: m_maint.setForeignObjects(fos);
217: Iterator itRel = upRel.iterator();
218: for (Iterator itDom = upDomain.iterator(); itDom
219: .hasNext();) {
220: org.jaffa.patterns.library.domain_creator_1_1.domain.Root domain = (org.jaffa.patterns.library.domain_creator_1_1.domain.Root) itDom
221: .next();
222: org.jaffa.patterns.library.domain_creator_1_1.domain.Relationship rel = (org.jaffa.patterns.library.domain_creator_1_1.domain.Relationship) itRel
223: .next();
224: log.debug("Maint Comp " + getComponentName()
225: + " - Processing Foriegn Object "
226: + domain.getDomainObject());
227:
228: ForeignObject fo = objFactory.createForeignObject();
229: fos.getForeignObject().add(fo);
230: fo.setObject(domain.getDomainObject());
231: fo.setPackage(domain.getDomainPackage());
232: ForeignFields ffs = objFactory
233: .createForeignFields();
234: fo.setForeignFields(ffs);
235:
236: // Loop through relationship fields
237: Iterator itToFlds = rel.getToFields()
238: .getRelationshipField().iterator();
239: for (Iterator itUpFlds = rel.getFromFields()
240: .getRelationshipField().iterator(); itUpFlds
241: .hasNext();) {
242: RelationshipField upFld = (RelationshipField) itUpFlds
243: .next();
244: RelationshipField toFld = (RelationshipField) itToFlds
245: .next();
246:
247: // If this field has been already used with another object....
248: // Then we have a conflict that needs to be resoved as the pattern does not
249: // support this get.
250: // In this case, skip this field in the foriegn object
251: if (processedFields.contains(toFld.getName())) {
252: log
253: .error("Field "
254: + toFld.getName()
255: + " attempted to be used on second foregin object "
256: + domain.getDomainObject());
257: /*
258: if(ffs.getForeignField().size()>0) {
259: // If any fields are already to be ignored, remove them from the processed list!
260: for(int i = 0; i<ffs.getForeignField().size(); i++) {
261: ForeignField x = (ForeignField)ffs.getForeignField().get(i);
262: processedFields.remove(x.getName());
263: }
264:
265: }
266: fos.getForeignObject().remove(fo);
267: break;
268: */
269: } else {
270: // Still add the foreign object, just miss out this key!
271:
272: ForeignField ff = objFactory
273: .createForeignField();
274: ffs.getForeignField().add(ff);
275:
276: // Field in this maintenance object
277: ff.setName(toFld.getName());
278: ff.setDomainField(toFld.getName());
279:
280: // Flag this field as processed, so its not used in the 'Fields' section
281: processedFields.add(toFld.getName());
282:
283: // Field in up entity
284: ff.setDomainFieldInForeignObject(upFld
285: .getName());
286:
287: log
288: .debug("Maint Comp "
289: + getComponentName()
290: + " - Processing Foriegn Field "
291: + ff.getDomainField()
292: + "->"
293: + ff
294: .getDomainFieldInForeignObject());
295:
296: // Now get this fields definition from the domain object for the other info....
297: for (Iterator itFindFld = m_domain
298: .getFields().getField().iterator(); itFindFld
299: .hasNext();) {
300: org.jaffa.patterns.library.domain_creator_1_1.domain.Field f = (org.jaffa.patterns.library.domain_creator_1_1.domain.Field) itFindFld
301: .next();
302: if (f.getName().equals(
303: ff.getDomainField())) {
304: // Found Field, use values
305: String dt = Defaults.getDataType(f
306: .getDataType());
307: if (dt == null)
308: throw new Exception(
309: "Can't Translate Java Class "
310: + f
311: .getDataType()
312: + " to a supported Data Type");
313: ff.setDataType(dt);
314: ff.setDisplay(true);
315: ff.setKeyType("Primary");
316: ff.setWidth("300px");
317: ff
318: .setMandatory(rel
319: .getFromCardinality() != null
320: && rel
321: .getFromCardinality()
322: .startsWith(
323: "1"));
324: ff.setLabel(f.getLabelToken());
325: break;
326: }
327: }
328:
329: // Error if never found...should not happen.!
330: if (ff.getDataType() == null)
331: throw new Exception(
332: "Didn't Find Field Definition for "
333: + ff.getDomainField()
334: + " in "
335: + m_domain
336: .getDomainObject());
337: }
338: }
339: }
340: }
341:
342: // Make sure there are some fields!
343: int fieldCount = 0;
344: List fields = m_domain.getFields().getField();
345: if (fields == null || fields.isEmpty()) {
346: log
347: .error("Domain Object "
348: + m_domain.getDomainObject()
349: + " has no fields, this is needed to build a valid Maintenance");
350: } else {
351:
352: // Add all the key fields
353: KeyFields kfields = objFactory.createKeyFields();
354: m_maint.setKeyFields(kfields);
355: Fields ifields = objFactory.createFields();
356: m_maint.setFields(ifields);
357: for (Iterator it1 = fields.iterator(); it1.hasNext();) {
358: org.jaffa.patterns.library.domain_creator_1_1.domain.Field fld = (org.jaffa.patterns.library.domain_creator_1_1.domain.Field) it1
359: .next();
360:
361: if (fld.getPrimaryKey().equalsIgnoreCase("t")) {
362: KeyField kfld = objFactory.createKeyField();
363: kfields.getKeyField().add(kfld);
364:
365: kfld.setName(reservedName(fld.getName()));
366:
367: String dt = Defaults.getDataType(fld
368: .getDataType());
369: if (dt == null)
370: throw new Exception(
371: "Can't Translate Java Class "
372: + fld.getDataType()
373: + " to a supported Data Type");
374: kfld.setDataType(dt);
375: kfld.setDomainField(fld.getName());
376: }
377:
378: // Only process field if not a foreign object field
379: if (!processedFields.contains(fld.getName())) {
380: fieldCount++;
381: Field ifld = objFactory.createField();
382: ifields.getField().add(ifld);
383:
384: ifld.setName(reservedName(fld.getName()));
385: String dt = Defaults.getDataType(fld
386: .getDataType());
387: if (dt == null)
388: throw new Exception(
389: "Can't Translate Java Class "
390: + fld.getDataType()
391: + " to a supported Data Type");
392: ifld.setDataType(dt);
393:
394: ifld.setDisplay(true);
395: ifld.setLabel("[" + labelDomain + "."
396: + fld.getName() + "]");
397: ifld.setWidth("300px");
398: ifld.setDomainField(fld.getName());
399: }
400: }
401:
402: if (fieldCount == 0) {
403: log
404: .warn("All fields consumed by foriegn objects!. Dummy Inserted");
405: // Should really compensate for this in the pattern!!
406: Field ifld = objFactory.createField();
407: ifields.getField().add(ifld);
408: ifld.setName("Dummy");
409: ifld.setDataType("String");
410: ifld.setDisplay(false);
411: ifld.setMandatory(false);
412: ifld.setLabel("Dummy Label");
413: ifld.setWidth("300px");
414: ifld.setDomainField("");
415: }
416: }
417: } catch (JAXBException e) {
418: log.error("Failed to create Maintenance Object");
419: }
420: }
421:
422: /** Saves the generated meta data to the prespecified location as an XML file
423: * NOTE: assumes that the build(..) method has been called!
424: */
425: public boolean save() {
426: String filename = m_app.getOutputRoot()
427: + m_app.getOutputMaintenance()
428: + m_domain.getDomainObject() + "Maintenance.xml";
429: File file = new File(filename);
430: File path = new File(file.getParent());
431: if (!path.exists())
432: path.mkdirs();
433:
434: // Create output stream
435: FileOutputStream out = null;
436: try {
437: try {
438: out = new FileOutputStream(file.getPath());
439: } catch (FileNotFoundException e) {
440: log.error("Failed to open output stream !", e);
441: return false;
442: }
443:
444: try {
445: // create a JAXBContext capable of handling classes generated into the package
446: JAXBContext jc = JAXBContext
447: .newInstance("org.jaffa.patterns.library.object_maintenance_meta_1_0.domain");
448: // create a Validator
449: Validator v = jc.createValidator();
450: ValidationEventCollector valErrors = new ValidationEventCollector();
451: v.setEventHandler(valErrors);
452: // validate the content tree
453: if (!v.validateRoot(m_maint)) {
454: log.error("Failed to validate Structure !");
455: JAXBHelper.showErrors(log, valErrors);
456: return false;
457: }
458:
459: // Write out XML document to file
460: Marshaller m = jc.createMarshaller();
461:
462: //m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
463: //m.marshal(m_maint, out);
464: JAXBHelper
465: .marshalWithDocType(
466: m,
467: m_maint,
468: out,
469: "Root",
470: "-//JAFFA//DTD Object Maintenance Meta 1.0//EN",
471: "http://jaffa.sourceforge.net/DTD/object-maintenance-meta_1_0.dtd");
472:
473: } catch (ValidationException e) {
474: log.error("Failed to validate Structure !", e);
475: return false;
476: } catch (JAXBException e) {
477: log
478: .error(
479: "Failed to marshal xml to output stream !",
480: e);
481: return false;
482: }
483: } finally {
484: if (out != null)
485: try {
486: out.close();
487: } catch (IOException e) {
488: }
489: }
490: return true;
491: }
492:
493: private static List reservedAttr = null;
494: static {
495: reservedAttr = new ArrayList();
496: reservedAttr.add("component");
497: }
498:
499: private String reservedName(String name) {
500: if (reservedAttr.contains(name.toLowerCase()))
501: return name + "1";
502: else
503: return name;
504: }
505:
506: public String getApplication() {
507: return m_maint.getApplication();
508: }
509:
510: public String getComponentControllerClass() {
511: return m_maint.getComponent() + "Component";
512: }
513:
514: public String getComponentControllerPackage() {
515: return m_maint.getBasePackage() + ".components."
516: + m_maint.getComponent().toLowerCase() + ".ui";
517: }
518:
519: public String getComponentName() {
520: return getModule() + "."
521: + StringHelper.getUpper1(m_maint.getComponent());
522: }
523:
524: public String getComponentType() {
525: return "Maintenance";
526: }
527:
528: public String getDomain() {
529: return m_maint.getDomainPackage() + "."
530: + m_maint.getDomainObject();
531: }
532:
533: public String getModule() {
534: return StringHelper.getUpper1(m_maint.getModule());
535: }
536:
537: public String getName() {
538: return StringHelper.getUpper1(m_maint.getComponent());
539: }
540:
541: /** Causes the meta data object to be build ready for saving.
542: * @param fullPackage If true then the .applications. and .modules. package names
543: * are used. If this is false, these are ommited for a much more condensed package
544: * naming convention
545: */
546: public void buildPhase2(boolean fullPackage) throws Exception {
547: ObjectFactory objFactory = new ObjectFactory();
548: try {
549: // For foreign object, link to there lookups...
550: if (m_maint.getForeignObjects() != null
551: && m_maint.getForeignObjects().getForeignObject() != null) {
552:
553: for (Iterator it = m_maint.getForeignObjects()
554: .getForeignObject().iterator(); it.hasNext();) {
555: ForeignObject fo = (ForeignObject) it.next();
556: IBuilder comp = m_compReg.findComponent(fo
557: .getPackage()
558: + "." + fo.getObject(), "Lookup");
559: // Found lookup
560: if (comp != null) {
561: Lookup lookup = objFactory.createLookup();
562: fo.setLookup(lookup);
563: lookup.setBypassCriteriaScreen(true);
564: lookup.setComponent(comp.getComponentName());
565: String x = null; // This is of the form "lookupfld=maintfld;.."
566: String y = null; // This is of the form "maintfld=lookupfld;.."
567: for (Iterator it2 = fo.getForeignFields()
568: .getForeignField().iterator(); it2
569: .hasNext();) {
570: ForeignField ff = (ForeignField) it2.next();
571: String maintFld = StringHelper.getLower1(ff
572: .getName());
573: String lookupFld = StringHelper
574: .getLower1(ff
575: .getDomainFieldInForeignObject());
576: x = (x == null ? "" : x + ";") + lookupFld
577: + "=" + maintFld;
578: y = (y == null ? "" : y + ";") + maintFld
579: + "=" + lookupFld;
580: }
581: if (x != null)
582: lookup.setDynamicParameters(x);
583: if (y != null)
584: lookup.setTargetFields(y);
585: lookup.setStaticParameters(""); // should make this optional in pattern!
586: } else
587: log.warn("Lookup Not Found for "
588: + fo.getObject());
589: }
590: }
591:
592: } catch (JAXBException e) {
593: log.error("Failed to create Maintenance Object");
594: }
595: }
596:
597: }
|