001: package com.xoetrope.data.pojo;
002:
003: import com.xoetrope.carousel.visualizer.TreeNodeCaption;
004: import java.io.BufferedReader;
005: import java.io.IOException;
006: import java.io.InputStream;
007: import java.lang.reflect.Method;
008: import java.util.ArrayList;
009: import java.util.Enumeration;
010: import java.util.Hashtable;
011: import java.util.Iterator;
012: import java.util.List;
013: import net.xoetrope.debug.DebugLogger;
014: import net.xoetrope.xml.XmlElement;
015: import net.xoetrope.xml.XmlSource;
016: import net.xoetrope.xml.jaxp.JaxpXmlParser;
017: import net.xoetrope.xui.XProject;
018: import net.xoetrope.xui.data.XModel;
019: import org.xml.sax.EntityResolver;
020: import org.xml.sax.InputSource;
021: import org.xml.sax.SAXException;
022:
023: public class XHibernatePojoDataSourceEx extends
024: XPersistentPojoDataSourceEx {
025: // the names of the collections that can occur in Hibernate mapping files
026: private static final String[] COLLECTION_TYPES = { "bag", "idbag",
027: "set", "list", "map" };
028:
029: // the fetch types that specifie non-lazily initialized collections
030: private static final String[] FETCH_TYPES = { "join", "select",
031: "subselect" };
032:
033: // stores the configuration of hibernate lazily initialized collections
034: protected Hashtable hibernateConfiguration;
035:
036: // an xml parsner used to parse Hibernate mapping files
037: protected JaxpXmlParser xmlParser;
038:
039: /**
040: * Creates a new instance of XHibernatePojODataSourceEx
041: * @param project the owner project
042: */
043: public XHibernatePojoDataSourceEx(XProject project) {
044: super (project);
045: hibernateConfiguration = new Hashtable();
046: xmlParser = JaxpXmlParser.getInstance(project);
047: xmlParser.setEntityResolver(new XHibernateEntityResolver());
048: readMappingFiles();
049: }
050:
051: /**
052: * Reads the Hibernate mapping files and configures the adapters
053: */
054: protected void readMappingFiles() {
055: // read mapping file names
056: List mappingFiles = new ArrayList();
057: try {
058: BufferedReader br = currentProject
059: .getBufferedReader("hibernate.cfg.xml");
060: XmlElement rootXml = XmlSource.read(br).getFirstChildNamed(
061: "session-factory");
062: if (rootXml != null) {
063: Enumeration enumChildren = rootXml.getChildren()
064: .elements();
065:
066: // iterate over the children
067: while (enumChildren.hasMoreElements()) {
068: XmlElement childXml = (XmlElement) enumChildren
069: .nextElement();
070: if (!"mapping".equals(childXml.getName()))
071: continue;
072: // store the name of the mapping file
073: String fileName = childXml.getAttribute("resource");
074: if (fileName != null)
075: mappingFiles.add(fileName);
076: }
077: br.close();
078: }
079: } catch (Exception ex) {
080: DebugLogger
081: .logError("failed to read Hibernate mapping file names");
082: ex.printStackTrace();
083: return;
084: }
085:
086: // read the configuration from the mapping files
087: Iterator fileIter = mappingFiles.iterator();
088: while (fileIter.hasNext()) {
089: String fileName = (String) fileIter.next();
090: if (fileName != null)
091: readMappingFile(fileName);
092: }
093: }
094:
095: /**
096: * Configures the POJO adapters of the classes whose
097: * mapping configuration is contained in the specified Hibernate mapping file.
098: * @param fileName the name of the Hibernate mapping file
099: */
100: protected void readMappingFile(String fileName) {
101: try {
102: BufferedReader br = currentProject
103: .getBufferedReader(fileName);
104:
105: // get the mapping file content
106: XmlElement rootXml = xmlParser.parse(br);
107:
108: // get the package name whose classes are mapped
109: String packageName = rootXml.getAttribute("package");
110: if (packageName == null)
111: return;
112:
113: // read the entity definitions
114: Enumeration enumClasses = rootXml.getChildren().elements();
115: while (enumClasses.hasMoreElements()) {
116: // read the single class configuration
117: XmlElement classXml = (XmlElement) enumClasses
118: .nextElement();
119: if (!"class".equals(classXml.getName()))
120: continue;
121: String className = (packageName + "." + classXml
122: .getAttribute("name"));
123:
124: // iterate over the class properties
125: Enumeration enumProperties = classXml.getChildren()
126: .elements();
127: while (enumProperties.hasMoreElements()) {
128: // read the property configuration
129: XmlElement propertyXml = (XmlElement) enumProperties
130: .nextElement();
131:
132: // check whether the xml node defines a "lazy collection"
133: if (!isLazyCollection(propertyXml))
134: continue;
135:
136: // mark the collection as lazily initialized
137: String propertyName = propertyXml
138: .getAttribute("name");
139: List properties = (List) hibernateConfiguration
140: .get(className);
141: if (properties == null)
142: hibernateConfiguration.put(className,
143: properties = new ArrayList());
144: properties.add(propertyName);
145:
146: }
147: }
148: br.close();
149: } catch (Exception ex) {
150: DebugLogger
151: .logError("unable to read the file: " + fileName);
152: ex.printStackTrace();
153: }
154: }
155:
156: /**
157: * Indicates whether the specified xml node specifies a Hibernate lazily
158: * initialized collection.
159: * @param propertyXml xml node describing POJO property, it should belong
160: * to a Hibernate entity mapping file.
161: */
162: private boolean isLazyCollection(XmlElement propertyXml) {
163: if (propertyXml == null)
164: return false;
165:
166: // check if the given xml node specifies a collection
167: String propertyType = propertyXml.getName();
168: boolean ic = false;
169: for (int i = 0; !ic && (i < COLLECTION_TYPES.length); i++)
170: ic = COLLECTION_TYPES[i].equalsIgnoreCase(propertyType);
171: if (!ic)
172: return false; // the property doesn't define a collection
173:
174: // check if the collection is lazily initialized
175: String fetchType = propertyXml.getAttribute("fetch");
176:
177: if (fetchType == null)
178: return true; // no "fetch" attribute, collection is lazy
179:
180: // check the value of the "fetch" attribute
181: boolean il = true;
182: for (int i = 0; il && (i < FETCH_TYPES.length); i++)
183: il = !FETCH_TYPES[i].equalsIgnoreCase(fetchType);
184:
185: return il;
186: }
187:
188: /**
189: * Overrides the adapter, adds the customization specified by
190: * the configuration and Hibernate mapping files.
191: * @param adapter the adpater to be customized
192: */
193: public void overrideAdapter(XPojoAdapterEx adapter) {
194: // get the adapted class name
195: String className = adapter.getAdaptedClass().getName();
196: // get the list of lazily initialized properties
197: List properties = (List) hibernateConfiguration.get(className);
198: if (properties != null) {
199: XPersistentPojoAdapterEx ad = (XPersistentPojoAdapterEx) adapter;
200: // iterate over the properties
201: Iterator propertiesIter = properties.iterator();
202: while (propertiesIter.hasNext()) {
203: String propertyName = (String) propertiesIter.next();
204: ad.setTransaction(propertyName);
205: }
206: }
207: super .overrideAdapter(adapter);
208: }
209:
210: /**
211: * An entity resolver used to avoid loading remote DTD files.
212: */
213: private class XHibernateEntityResolver implements EntityResolver {
214: public InputSource resolveEntity(String publicID,
215: String systemID) throws SAXException {
216: InputSource inputSource = null;
217: // don't load DTD files
218: if (systemID.endsWith(".dtd")) {
219: // create an empty InputStream object
220: InputStream inputStream = (new InputStream() {
221: public int read() throws IOException {
222: return -1;
223: }
224: });
225: // no-data inputSource object
226: inputSource = new InputSource(inputStream);
227: }
228: return inputSource;
229: }
230: }
231:
232: }
|