001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019:
020: /*
021: *
022: * Copyright 2005 Sun Microsystems, Inc.
023: *
024: * Licensed under the Apache License, Version 2.0 (the "License");
025: * you may not use this file except in compliance with the License.
026: * You may obtain a copy of the License at
027: *
028: * http://www.apache.org/licenses/LICENSE-2.0
029: *
030: * Unless required by applicable law or agreed to in writing, software
031: * distributed under the License is distributed on an "AS IS" BASIS,
032: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
033: * See the License for the specific language governing permissions and
034: * limitations under the License.
035: *
036: */
037:
038: package org.netbeans.modules.jdbcwizard.builder.xsd;
039:
040: import org.netbeans.modules.jdbcwizard.builder.dbmodel.DBColumn;
041: import org.netbeans.modules.jdbcwizard.builder.dbmodel.DBTable;
042: import org.netbeans.modules.jdbcwizard.builder.dbmodel.impl.DBColumnImpl;
043: import org.netbeans.modules.jdbcwizard.builder.util.XMLCharUtil;
044:
045: import java.io.PrintWriter;
046: import java.io.File;
047: import java.io.FileOutputStream;
048: import java.util.List;
049:
050: import javax.xml.parsers.DocumentBuilderFactory;
051: import java.util.logging.Logger;
052: import org.w3c.dom.Document;
053: import org.w3c.dom.Element;
054:
055: /**
056: * @author This class generates an XML schema for every created OTD.
057: */
058: public class XSDGenerator {
059: private static final Logger mLogger = Logger.getLogger("JDBC"
060: + XSDGenerator.class.getName());
061:
062: private static final String INDENT = " ";
063:
064: private static final String XSD_PREFIX = "xsd:";
065:
066: private static final String XMLNS = "xmlns";
067:
068: private static final String NS_XSD = "xmlns:xsd";
069:
070: private static final String TARGET_NS = "targetNamespace";
071:
072: private static final String ELEMENT_FORM_DEFAULT = "elementFormDefault";
073:
074: private static final String XSD_SEQUENCE = "sequence";
075:
076: private static final String XSD_ELEMENT = "element";
077:
078: private static final String XSD_COMPLEX_TYPE = "complexType";
079:
080: private static final String NAME_ATTR = "name";
081:
082: private static final String TYPE_ATTR = "type";
083:
084: private static final String MAX_OCCURS_ATTR = "maxOccurs";
085:
086: private static final String TARGETNAMESPACE = "http://j2ee.netbeans.org/xsd/tableSchema";
087:
088: private Document mDoc;
089:
090: // private Document mRepeatStructDoc;
091: private Element mRoot;
092:
093: private Element mCurrentNode;
094:
095: private String mFileName = "";
096:
097: private String mRepeatStructFileName = "";
098:
099: // private String mOtdName = "";
100: // private List mTables = null;
101: // private List mDbObjects = null;
102: private DBTable ltbl = null;
103:
104: public XSDGenerator() throws Exception {// Need to revisit the object type
105: }
106:
107: public void generate(final String aPrjPath, final String aFileName,
108: final DBTable tbl) throws Exception {
109: this .mFileName = aFileName;
110: // mOtdName = aOtdName;
111: if (this .mFileName != null && !this .mFileName.trim().equals("")) {
112: final File aFile = new File(this .mFileName);
113: if (!aFile.getName().endsWith(".xsd")
114: && !aFile.getName().endsWith(".XSD")) {
115: throw new Exception(
116: "Found invalid XSD file name: "
117: + aFile.getName()
118: + ". Please make sure that the XSD file name has \".xsd\" suffix.");
119: }
120: final String newFileName = aFile.getName().substring(0,
121: aFile.getName().lastIndexOf(".xsd"))
122: + "_s.xsd";
123: this .mRepeatStructFileName = aFile.getParent()
124: + File.separator + newFileName;
125: }
126: this .ltbl = tbl;
127: this .generateSimpleXsd();
128: this .resetElements();
129: // generateRepeatXsd();
130:
131: }
132:
133: public void generateSimpleXsd() throws Exception {
134: this .generateXSDHeaders();
135: final Element aNode = this .addElementNode(XMLCharUtil
136: .makeValidNCName(this .ltbl.getName()));
137: this .mCurrentNode = aNode;
138: this .createComplexTypesForTables(this .ltbl);
139: this .serialize(this .mFileName);
140: }
141:
142: public void generateRepeatXsd() throws Exception {
143: this .generateXSDHeaders();
144:
145: final String tableName = XMLCharUtil.makeValidNCName(this .ltbl
146: .getName());
147: final String complexTypeName = tableName + "List";
148: final Element aNode = this .addElementNode(tableName + "_List",
149: complexTypeName);
150: this .createComplexTypeRepeatElement(complexTypeName, tableName);
151: this .createComplexTypesForTables(this .ltbl);
152: this .serialize(this .mRepeatStructFileName);
153: }
154:
155: private void generateXSDHeaders() throws Exception {
156: this .createDocuments();
157: this .mRoot = this .mDoc.createElement(XSDGenerator.XSD_PREFIX
158: + "schema");
159: this .mRoot.setAttribute(XSDGenerator.NS_XSD,
160: "http://www.w3.org/2001/XMLSchema");
161: this .mRoot.setAttribute(XSDGenerator.TARGET_NS,
162: XSDGenerator.TARGETNAMESPACE);
163: this .mRoot.setAttribute(XSDGenerator.ELEMENT_FORM_DEFAULT,
164: "qualified");
165: this .mRoot.setAttribute(XSDGenerator.XMLNS,
166: XSDGenerator.TARGETNAMESPACE);
167: this .mDoc.appendChild(this .mRoot);
168: this .mCurrentNode = this .mRoot;
169: }
170:
171: private Element addElementNode(final String name) {
172: final Element aElement = this .mDoc
173: .createElement(XSDGenerator.XSD_PREFIX
174: + XSDGenerator.XSD_ELEMENT);
175: aElement.setAttribute(XSDGenerator.NAME_ATTR, name);
176: aElement.setAttribute(XSDGenerator.TYPE_ATTR, name);
177: this .mCurrentNode.appendChild(aElement);
178:
179: return aElement;
180: }
181:
182: private Element addElementNode(final String name, final String type) {
183: final Element aElement = this .mDoc
184: .createElement(XSDGenerator.XSD_PREFIX
185: + XSDGenerator.XSD_ELEMENT);
186: aElement.setAttribute(XSDGenerator.NAME_ATTR, name);
187: aElement.setAttribute(XSDGenerator.TYPE_ATTR, type);
188: this .mCurrentNode.appendChild(aElement);
189:
190: return aElement;
191: }
192:
193: private void createComplexTypesForTables(final DBTable aTable)
194: throws Exception {
195: final List cols = aTable.getColumnList();
196: Element aNode = null;
197: final String tableName = XMLCharUtil.makeValidNCName(aTable
198: .getName());
199:
200: aNode = this .mDoc.createElement(XSDGenerator.XSD_PREFIX
201: + XSDGenerator.XSD_COMPLEX_TYPE);
202: aNode.setAttribute(XSDGenerator.NAME_ATTR, tableName);
203: this .mRoot.appendChild(aNode);
204: this .mCurrentNode = aNode;
205:
206: if (cols.size() > 0) {
207: aNode = this .mDoc.createElement(XSDGenerator.XSD_PREFIX
208: + XSDGenerator.XSD_SEQUENCE);
209: aNode.setAttribute(XSDGenerator.MAX_OCCURS_ATTR,
210: "unbounded");
211: this .mCurrentNode.appendChild(aNode);
212: this .mCurrentNode = aNode;
213: }
214:
215: this .createColumnElements(cols);
216: this .mCurrentNode = this .mRoot;
217: }
218:
219: private void createColumnElements(final List cols) throws Exception {
220: Element aNode = null;
221: for (int ii = 0; ii < cols.size(); ii++) {
222: final DBColumn iCol = (DBColumn) cols.get(ii);
223: final DBColumnImpl colDesc = iCol instanceof DBColumnImpl ? (DBColumnImpl) iCol
224: : new DBColumnImpl();
225: colDesc.copyFrom(iCol);
226: final String colName = colDesc.getJavaName();
227: final int javaType = colDesc.getJdbcType();
228: String colType = (String) TypeUtil.SQLTOJAVATYPES
229: .get(TypeUtil.getSQLTypeDescription(javaType));
230:
231: if (!TypeUtil.isBuiltInType(colType)) {
232: XSDGenerator.mLogger
233: .severe("Encountered invalid data type of ["
234: + colType + "]");
235: // throw new Exception("Encountered invalid data type of [" + colType + "]");
236: } else {
237: colType = (String) TypeUtil.builtInTypes.get(colType);
238: }
239:
240: aNode = this .mDoc.createElement(XSDGenerator.XSD_PREFIX
241: + XSDGenerator.XSD_ELEMENT);
242: aNode.setAttribute(XSDGenerator.NAME_ATTR, colName);
243: aNode.setAttribute(XSDGenerator.TYPE_ATTR, colType);// defaulted for time being
244: // aNode.setAttribute(MIN_OCCURS_ATTR, "0");
245: // aNode.setAttribute(MAX_OCCURS_ATTR, "unbounded");
246: this .mCurrentNode.appendChild(aNode);
247: }
248: }
249:
250: private void createComplexTypeRepeatElement(final String typeName,
251: final String elemName) {
252: Element aNode = this .mDoc.createElement(XSDGenerator.XSD_PREFIX
253: + XSDGenerator.XSD_COMPLEX_TYPE);
254: aNode.setAttribute(XSDGenerator.NAME_ATTR, typeName);
255: this .mRoot.appendChild(aNode);
256: this .mCurrentNode = aNode;
257: aNode = this .mDoc.createElement(XSDGenerator.XSD_PREFIX
258: + XSDGenerator.XSD_SEQUENCE);
259: aNode.setAttribute(XSDGenerator.MAX_OCCURS_ATTR, "unbounded");
260: this .mCurrentNode.appendChild(aNode);
261: this .mCurrentNode = aNode;
262: aNode = this .mDoc.createElement(XSDGenerator.XSD_PREFIX
263: + XSDGenerator.XSD_ELEMENT);
264: aNode.setAttribute(XSDGenerator.NAME_ATTR, elemName);
265: aNode.setAttribute(XSDGenerator.TYPE_ATTR, elemName);
266: // aNode.setAttribute(MIN_OCCURS_ATTR, "0");
267: // aNode.setAttribute(MAX_OCCURS_ATTR, "unbounded");
268: this .mCurrentNode.appendChild(aNode);
269: }
270:
271: private void resetElements() {
272: this .mDoc = null;
273: this .mRoot = null;
274: this .mCurrentNode = null;
275: }
276:
277: public void serialize(final String filename) throws Exception {
278: try {
279: final File lFile = new File(this .mFileName);
280: final File lParent = lFile.getParentFile();
281: if (!lParent.exists()) {
282: lParent.mkdirs();
283: }
284: /**
285: * Original design was to prompt the user for a directory name to create an XSD file
286: * with a name that matches the OTD names and a file extension of .xsd Because of the
287: * difficulties with the GUI design, we will settle for a user-entered file name for
288: * now.
289: */
290: final PrintWriter pw = new PrintWriter(
291: new FileOutputStream(new File(filename)));
292: final DOMWriter dw = new DOMWriter(pw, false);
293: dw.print(XSDGenerator.INDENT, this .mDoc, true);
294: } catch (final Exception e) {
295: XSDGenerator.mLogger
296: .severe("Failed to serialize XSD document: "
297: + e.getMessage());
298: throw new Exception("Failed to serialize XSD document: "
299: + e.getMessage());
300: }
301: }
302:
303: private void createDocuments() throws Exception {
304: try {
305: final DocumentBuilderFactory dbf = DocumentBuilderFactory
306: .newInstance();
307: synchronized (dbf) {
308: dbf.setNamespaceAware(true);
309: this .mDoc = dbf.newDocumentBuilder().newDocument();
310: if (this .mDoc == null) {
311: XSDGenerator.mLogger
312: .severe("Failed to create Document object");
313: throw new Exception(
314: "Failed to create Document object.");
315: }
316: }
317: } catch (final Exception e) {
318: XSDGenerator.mLogger
319: .severe("Failed to create XSD Document: "
320: + e.getMessage());
321: throw new Exception("Failed to create XSD Document: "
322: + e.getMessage());
323: }
324: }
325: }
|