001    package org.apache.torque.task;
002    
003    import java.io.File;
004    import java.io.FileWriter;
005    import java.io.IOException;
006    import java.io.StringWriter;
007    
008    import javax.xml.parsers.DocumentBuilder;
009    import javax.xml.parsers.DocumentBuilderFactory;
010    import javax.xml.parsers.ParserConfigurationException;
011    import javax.xml.transform.OutputKeys;
012    import javax.xml.transform.Result;
013    import javax.xml.transform.Transformer;
014    import javax.xml.transform.TransformerFactory;
015    import javax.xml.transform.dom.DOMSource;
016    import javax.xml.transform.stream.StreamResult;
017    import javax.xml.xpath.XPath;
018    import javax.xml.xpath.XPathConstants;
019    import javax.xml.xpath.XPathFactory;
020    
021    import org.apache.tools.ant.BuildException;
022    import org.apache.tools.ant.Task;
023    import org.w3c.dom.Document;
024    import org.w3c.dom.Element;
025    import org.w3c.dom.NodeList;
026    import org.xml.sax.SAXException;
027    
028    /**
029     * This ant task will merge the schema-desc.xml with schema.xml, if
030     * schema-description.xml exists
031     * 
032     * @author Kuali Rice Team (kuali-rice@googlegroups.com)
033     * 
034     */
035    public class TorqueMergeXMLDoc extends Task {
036            
037            private static final String DESCRIPTION_ATTR = "description";
038            private static final String JAVA_NAME_ATTR = "javaName";
039            private static final String NAME_ATTR = "name";
040            private static final String COLUMN_ELEMENT = "column";
041            
042            private File schemaWithDesc;
043            private File dbSchema;
044            private String schemaWithDescString;
045            private String dbSchemaString;
046            private Document schemaWithDescDoc;
047            private Document dbSchemaDoc;
048            
049    
050            public void setDbSchemaString(String dbSchemaString) {          
051                    this.dbSchemaString = dbSchemaString;
052                    dbSchema = new File(dbSchemaString);
053    
054            }
055    
056            public void setSchemaWithDescString(String schemaWithDescString) {              
057                    this.schemaWithDescString = schemaWithDescString;
058                    schemaWithDesc = new File(schemaWithDescString);
059    
060            }
061    
062            public File getDbSchema() {
063                    return dbSchema;
064            }
065    
066            public void setSchemaWithDesc(String schemaWithDescString) {
067                    this.schemaWithDesc = new File(schemaWithDescString);
068    
069            }
070    
071            public void setDbSchema(String dbSchemaString) {
072                    this.dbSchema = new File(dbSchemaString);
073            }
074    
075            /**
076             * creates a document object from an input file
077             * 
078             * @param file
079             * @return Document object
080             * @throws ParserConfigurationException
081             * @throws SAXException
082             * @throws IOException
083             */
084            public static Document setDocument(File file)
085                            throws ParserConfigurationException, SAXException, IOException {
086                    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
087                                    .newInstance();
088                    DocumentBuilder documentBuilder;
089                    documentBuilder = documentBuilderFactory.newDocumentBuilder();
090                    Document XMLdocument = documentBuilder.parse(file);
091                    XMLdocument.getDocumentElement().normalize();
092                    return XMLdocument;
093            }
094    
095            /**
096             * performs the merge operation by taking two input files as input and then
097             * merges the file with description into the existing schema.xml file
098             * 
099             * @param schemaWithDesc
100             * @param dbSchema
101             */
102            public void mergeSchemas(File schemaWithDesc, File dbSchema) throws Exception {
103    
104                    schemaWithDescDoc = setDocument(schemaWithDesc);
105                    dbSchemaDoc = setDocument(dbSchema);
106                    dbSchemaDoc = createNewXML(dbSchemaDoc, schemaWithDescDoc);
107    
108            }
109    
110            /**
111             * merges the two xml document. The resulting document will be same as
112             * schema.xml except it will have a description attribute for all its tables
113             * and columns.
114             */
115            public Document createNewXML(Document dbSchemaDoc,
116                            Document schemaWithDescDoc) throws Exception {
117    
118                    XPath xpath = XPathFactory.newInstance().newXPath();
119                    
120                    NodeList listOfTablesInSchema = (NodeList)xpath.evaluate("/database/table", dbSchemaDoc, XPathConstants.NODESET);
121    
122                    for (int tableIndex = 0; tableIndex < listOfTablesInSchema.getLength(); tableIndex++) {
123                            Element tableElementInSchema = (Element)listOfTablesInSchema.item(tableIndex);
124                            String tableName = tableElementInSchema.getAttribute(NAME_ATTR);
125                            // search the schema-description.xml file for a corresponding entry that contains the description
126                            Element tableDescElem = (Element)xpath.evaluate("/database/table[@" + NAME_ATTR + "='" + tableName + "']", schemaWithDescDoc, XPathConstants.NODE);
127                            if (tableDescElem != null) {
128                                    String tableDescription = tableDescElem.getAttribute(DESCRIPTION_ATTR);
129                                    String tableJavaName = tableDescElem.getAttribute(JAVA_NAME_ATTR);
130                                    tableElementInSchema.setAttribute(DESCRIPTION_ATTR, tableDescription);
131                                    tableElementInSchema.setAttribute(JAVA_NAME_ATTR, tableJavaName);
132                                    NodeList columnElements = tableElementInSchema.getElementsByTagName(COLUMN_ELEMENT);
133                                    for (int columnIndex = 0; columnIndex < columnElements.getLength(); columnIndex++) {
134                                            // look for the column in the schema description file
135                                            Element columnElementInSchema = (Element)columnElements.item(columnIndex);
136                                            String columnName = columnElementInSchema.getAttribute(NAME_ATTR);
137                                            Element columnDescElement = null;
138                                            NodeList columnDescElements = tableDescElem.getElementsByTagName(COLUMN_ELEMENT);
139                                            for (int columnDescIndex = 0; columnDescIndex < columnDescElements.getLength(); columnDescIndex++) {
140                                                    Element element = (Element)columnDescElements.item(columnDescIndex);
141                                                    if (columnName.equals(element.getAttribute(NAME_ATTR))) {
142                                                            columnDescElement = element;
143                                                            break;
144                                                    }
145                                            }
146                                            if (columnDescElement != null) {
147                                                    String columnDescription = columnDescElement.getAttribute(DESCRIPTION_ATTR);
148                                                    String columnJavaName = columnDescElement.getAttribute(JAVA_NAME_ATTR);
149                                                    columnElementInSchema.setAttribute(DESCRIPTION_ATTR, columnDescription);
150                                                    columnElementInSchema.setAttribute(JAVA_NAME_ATTR, columnJavaName);
151                                            }
152                                    }
153                            }
154                    }
155                    return dbSchemaDoc;
156            }
157    
158            /**
159             * writes the document object to an output file
160             * 
161             * @param newXMLDocument
162             *            output xml document
163             */
164            public void writeXMLToFile(Document newXMLDocument) throws Exception {
165                    File dbSchema = this.getDbSchema();
166                    TransformerFactory tFactory = TransformerFactory.newInstance();
167    
168                    Transformer transformer = tFactory.newTransformer();
169                    transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
170                            "database.dtd");
171                    DOMSource domSource = new DOMSource(newXMLDocument);
172                    StringWriter writer = new StringWriter();
173                    Result result = new StreamResult(writer);
174                    transformer.transform(domSource, result);
175                    FileWriter fileWriter = new FileWriter(dbSchema);
176    
177                    if (dbSchema.exists()) {
178                            StringBuffer bufferedWriter = new StringBuffer(writer
179                                            .toString());
180                            fileWriter.write(bufferedWriter.toString());
181                            fileWriter.close();
182                            System.out.println("The data has been written");
183                    } else {
184                            System.out.println("This file is not exist");
185                    }
186            }
187    
188            @Override
189            public void execute() throws BuildException {
190                    setDbSchema(dbSchemaString);
191                    setSchemaWithDesc(schemaWithDescString);
192                    if (!schemaWithDesc.exists()) {
193                            System.out.println("no schema file with description can be located");
194                            return;
195                    }
196                    try {
197                            mergeSchemas(schemaWithDesc, dbSchema);
198                            writeXMLToFile(dbSchemaDoc);
199                    } catch (Exception e) {
200                            throw new BuildException(e);
201                    }
202            }
203            
204            
205    
206    }