001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.xml.wizard;
042:
043: import java.awt.event.ActionEvent;
044: import java.io.File;
045: import java.io.FileInputStream;
046: import java.io.IOException;
047: import java.util.ArrayList;
048: import java.util.Collections;
049: import java.util.HashMap;
050: import java.util.Iterator;
051: import java.util.List;
052: import java.util.Map;
053: import java.util.Map.Entry;
054: import java.util.Set;
055: import java.util.StringTokenizer;
056: import java.util.TreeSet;
057:
058: import javax.swing.JFileChooser;
059: import javax.swing.filechooser.FileFilter;
060:
061: import org.openide.NotifyDescriptor;
062: import org.openide.DialogDisplayer;
063: import org.openide.actions.ActionManager;
064: import org.openide.windows.WindowManager;
065:
066: import org.netbeans.api.xml.services.UserCatalog;
067:
068: import org.openide.filesystems.FileObject;
069: import org.openide.filesystems.FileUtil;
070: import org.openide.loaders.DataObject;
071: import org.openide.util.Lookup;
072: import org.openide.util.actions.SystemAction;
073: import javax.xml.xpath.XPath;
074: import javax.xml.xpath.XPathConstants;
075: import javax.xml.xpath.XPathFactory;
076: import javax.xml.namespace.NamespaceContext;
077: import org.netbeans.modules.xml.lib.AbstractUtil;
078: import org.openide.nodes.Node;
079: import org.xml.sax.InputSource;
080: import org.w3c.dom.NodeList;
081:
082: /**
083: * Collection of static support methods.
084: *
085: * @author Petr Kuzel
086: */
087: public class Util extends AbstractUtil {
088:
089: // last catalog directory
090: private static File lastDirectory;
091:
092: /** Default and only one instance of this class. */
093: public static final Util THIS = new Util();
094: public static final String NO_NAME_SPACE = "NO_NAME_SPACE"; //NOI18N
095:
096: /** Nobody can create instance of it, just me. */
097: private Util() {
098: }
099:
100: /**
101: * Prompts user for a Schema file.
102: * @param extensions a space separated list of file extensions
103: * @return filename or null if operation was cancelled.
104: */
105: public static File selectSchemaFile(final String extensions) {
106: JFileChooser chooser = new JFileChooser();
107:
108: chooser.setFileFilter(new FileFilter() {
109: public boolean accept(File f) {
110: if (f.isDirectory())
111: return true;
112: StringTokenizer token = new StringTokenizer(extensions,
113: " "); // NOI18N
114: while (token.hasMoreElements()) {
115: if (f.getName().endsWith(token.nextToken()))
116: return true;
117: }
118: return false;
119: }
120:
121: public String getDescription() {
122: return Util.THIS.getString("PROP_schema_mask"); // NOI18N
123: }
124: });
125:
126: if (lastDirectory != null) {
127: chooser.setCurrentDirectory(lastDirectory);
128: }
129:
130: chooser.setDialogTitle(Util.THIS
131: .getString("PROP_schema_dialog_name"));
132: while (chooser.showDialog(WindowManager.getDefault()
133: .getMainWindow(), Util.THIS
134: .getString("PROP_schema_select_button")) == JFileChooser.APPROVE_OPTION) {
135: File f = chooser.getSelectedFile();
136: lastDirectory = chooser.getCurrentDirectory();
137: if (f != null && f.isFile()) {
138: StringTokenizer token = new StringTokenizer(extensions,
139: " "); // NOI18N
140: while (token.hasMoreElements()) {
141: if (f.getName().endsWith(token.nextToken()))
142: return f;
143: }
144: }
145:
146: DialogDisplayer.getDefault().notify(
147: new NotifyDescriptor.Message(Util.THIS
148: .getString("MSG_inValidFile"),
149: NotifyDescriptor.WARNING_MESSAGE));
150: }
151: return null;
152: }
153:
154: /**
155: * Obtain all known DTD public IDs.
156: */
157: public static String[] getKnownDTDPublicIDs() {
158: UserCatalog catalog = UserCatalog.getDefault();
159: if (catalog != null) {
160: Set idSet = new TreeSet();
161: for (Iterator it = catalog.getPublicIDs(); it.hasNext();) {
162: String next = (String) it.next();
163: // exclude schema publicIDs
164: String nextLowerCase = next.toLowerCase();
165: if (!nextLowerCase.startsWith("schema:")
166: && !nextLowerCase.endsWith(".xsd")) { // NOI18N
167: idSet.add(next);
168: }
169: }
170: return (String[]) idSet.toArray(new String[idSet.size()]);
171: } else {
172: Util.THIS.debug("Note SourceResolver not found!"); // NOI18N
173: return new String[0];
174: }
175: }
176:
177: /**
178: * Perform default action on specified data object.
179: */
180: public static void performDefaultAction(DataObject dataObject) {
181:
182: Node node = dataObject.getNodeDelegate();
183: SystemAction action = node.getDefaultAction();
184:
185: if (action != null) {
186: ActionManager manager = (ActionManager) Lookup.getDefault()
187: .lookup(ActionManager.class);
188: manager.invokeAction(action, new ActionEvent(node,
189: ActionEvent.ACTION_PERFORMED, "")); // NOI18N
190: }
191: }
192:
193: public static String getDocumentType() {
194: return "xsd";
195: }
196:
197: public static Map getFiles2NSMappingInProj(File rootFile,
198: String docType) {
199: List fileList = getFilesWithExtension(rootFile, docType,
200: new ArrayList());
201: Map result = new HashMap();
202: String xpathQuery = "//xsd:schema/@targetNamespace";
203:
204: for (int i = 0; i < fileList.size(); i++) {
205: File file = (File) fileList.get(i);
206:
207: if (Thread.currentThread().isInterrupted())
208: //if interrupted by the client dump the result and immediately return
209: break;
210: List targetNSList = null;
211: try {
212: targetNSList = runXPathQuery(file, xpathQuery);
213: String targetNS = null;
214: FileObject fobj = FileUtil.toFileObject(file);
215: if (targetNSList.size() > 0) {
216: //just take the first and ignore rest
217: targetNS = (String) targetNSList.get(0);
218: } else {
219: targetNS = NO_NAME_SPACE;
220: }
221: if ((targetNS == NO_NAME_SPACE))
222: //this is wsdl and it must have NS so ignore this file
223: continue;
224: result.put(fobj, targetNS);
225: } catch (Exception ex) {
226: //ex.printStackTrace();
227: //ignore this route
228: }
229: }
230: return result;
231: }
232:
233: public static List getFilesWithExtension(File startFile,
234: String fileExtension, List curList) {
235: if (Thread.currentThread().isInterrupted())
236: //if interrupted by the client dump the result and immediately return
237: return curList;
238: if (curList == null)
239: curList = new ArrayList();
240: if (startFile.isFile()) {
241: int index = startFile.getName().lastIndexOf(".");
242: if (index != -1) {
243: String extn = startFile.getName().substring(index + 1);
244: if ((extn != null)
245: && (extn.equalsIgnoreCase(fileExtension)))
246: curList.add(startFile);
247: }
248: }
249: if (startFile.isDirectory()) {
250: File[] children = startFile.listFiles();
251: if (children != null) {
252: for (int i = 0; i < children.length; i++) {
253: File child = (File) children[i];
254: getFilesWithExtension(child, fileExtension, curList);
255: }
256: }
257: }
258: return curList;
259: }
260:
261: public static List runXPathQuery(File parsedFile, String xpathExpr)
262: throws Exception {
263: List result = new ArrayList();
264: XPath xpath = XPathFactory.newInstance().newXPath();
265: xpath.setNamespaceContext(getNamespaceContext());
266:
267: InputSource inputSource = new InputSource(new FileInputStream(
268: parsedFile));
269: NodeList nodes = (NodeList) xpath.evaluate(xpathExpr,
270: inputSource, XPathConstants.NODESET);
271: if ((nodes != null) && (nodes.getLength() > 0)) {
272: for (int i = 0; i < nodes.getLength(); i++) {
273: org.w3c.dom.Node node = nodes.item(i);
274: result.add(node.getNodeValue());
275: }
276: }
277: return result;
278: }
279:
280: public static String getNamespace(FileObject fobj) {
281: SchemaParser parser = new SchemaParser();
282: File file = FileUtil.toFile(fobj);
283: // String systemId = file.getAbsolutePath();
284: // try {
285: // URL context = fobj.getURL();
286: // //#25604 workaround
287: // if (context.toExternalForm().endsWith("/") == false) {
288: // context = new URL(context.toExternalForm() + "/");
289: // }
290: // if (context != null) {
291: // systemId = new URL(context, systemId).toExternalForm();
292: // }
293: // } catch (MalformedURLException ex) {
294: // // ignore it use one passes by user
295: // } catch(FileStateInvalidException e){
296: //
297: // }
298: SchemaParser.SchemaInfo info = parser.parse(file.toURI()
299: .toString());
300:
301: if (info == null)
302: return null;
303:
304: return info.namespace;
305:
306: }
307:
308: public static SchemaParser.SchemaInfo getRootElements(
309: FileObject fobj) {
310: SchemaParser parser = new SchemaParser();
311: File file = FileUtil.toFile(fobj);
312: // String systemId = file.getAbsolutePath();
313: // try {
314: // URL context = fobj.getURL();
315: // //#25604 workaround
316: // if (context.toExternalForm().endsWith("/") == false) {
317: // context = new URL(context.toExternalForm() + "/");
318: // }
319: // if (context != null) {
320: // systemId = new URL(context, systemId).toExternalForm();
321: // }
322: // } catch (MalformedURLException ex) {
323: // // ignore it use one passes by user
324: // } catch(FileStateInvalidException e){
325: //
326: // }
327: SchemaParser.SchemaInfo info = parser.parse(file.toURI()
328: .toString());
329:
330: if (info == null)
331: return null;
332: else
333: return info;
334:
335: }
336:
337: public static String getRelativePath(File file, File relativeTo)
338: throws IOException {
339: File origFile = file;
340: File origRelativeTo = relativeTo;
341: List filePathStack = new ArrayList();
342:
343: //are they on the same drive?
344: String origFilePath = file.getAbsolutePath();
345: String relativeFile = relativeTo.getAbsolutePath();
346:
347: StringTokenizer str = new StringTokenizer(origFilePath, ":");
348: String drive = null, rdrive = null;
349: if (str.hasMoreTokens())
350: drive = str.nextToken();
351:
352: str = new StringTokenizer(relativeFile, ":");
353: if (str.hasMoreTokens())
354: rdrive = str.nextToken();
355: if (drive != null && rdrive != null) {
356: if (!drive.equals(rdrive)) {
357: return file.toURI().toString();
358: }
359: }
360:
361: List relativeToPathStack = new ArrayList();
362: // build the path stack info to compare it afterwards
363: file = file.getCanonicalFile();
364: while (file != null) {
365: filePathStack.add(0, file);
366: file = file.getParentFile();
367: }
368: relativeTo = relativeTo.getCanonicalFile();
369: while (relativeTo != null) {
370: relativeToPathStack.add(0, relativeTo);
371: relativeTo = relativeTo.getParentFile();
372: }
373: // compare as long it goes
374: int count = 0;
375: file = (File) filePathStack.get(count);
376: relativeTo = (File) relativeToPathStack.get(count);
377: while ((count < filePathStack.size() - 1)
378: && (count < relativeToPathStack.size() - 1)
379: && file.equals(relativeTo)) {
380: count++;
381: file = (File) filePathStack.get(count);
382: relativeTo = (File) relativeToPathStack.get(count);
383: }
384: if (file.equals(relativeTo))
385: count++;
386: // up as far as necessary
387:
388: StringBuffer relString = new StringBuffer();
389: for (int i = count; i < relativeToPathStack.size(); i++) {
390: relString.append(".." + File.separator);
391: }
392: // now back down to the file
393: for (int i = count; i < filePathStack.size() - 1; i++) {
394: relString.append(((File) filePathStack.get(i)).getName()
395: + File.separator);
396: }
397: relString.append(((File) filePathStack
398: .get(filePathStack.size() - 1)).getName());
399: // just to test
400: // File relFile = new File(origRelativeTo.getAbsolutePath()+File.separator+relString.toString());
401: // if (!relFile.getCanonicalFile().equals(origFile.getCanonicalFile())) {
402: // throw new IOException("Failed to find relative path.");
403: // }
404: return relString.toString();
405: }
406:
407: private static Map namespaces = new HashMap();
408: private static Map prefixes = new HashMap();
409:
410: private static NamespaceContext getNamespaceContext() {
411: //schema related
412: namespaces.put("xsd", "http://www.w3.org/2001/XMLSchema");
413: prefixes.put("http://www.w3.org/2001/XMLSchema", "xsd");
414:
415: return new HashNamespaceResolver(namespaces, prefixes);
416: }
417:
418: public static final class HashNamespaceResolver implements
419: NamespaceContext {
420: private Map prefixes; // namespace, prefix
421: private Map namespaces; // prefix, namespace
422:
423: public HashNamespaceResolver(Map nsTable) {
424: namespaces = nsTable;
425: prefixes = new HashMap();
426: Set set = namespaces.entrySet();
427: Iterator it = set.iterator();
428: while (it.hasNext()) {
429: //for (Entry<String,String> e : namespaces.entrySet()) {
430: Entry e = (Entry) it.next();
431: prefixes.put(e.getValue(), e.getKey());
432: }
433: }
434:
435: public HashNamespaceResolver(Map namespaces, Map prefixes) {
436: this .namespaces = namespaces;
437: this .prefixes = prefixes;
438: }
439:
440: public Iterator getPrefixes(String namespaceURI) {
441: return Collections.singletonList(getPrefix(namespaceURI))
442: .iterator();
443: }
444:
445: public String getPrefix(String namespaceURI) {
446: return (String) prefixes.get(namespaceURI);
447: }
448:
449: public String getNamespaceURI(String prefix) {
450: return (String) namespaces.get(prefix);
451: }
452: }
453:
454: }
|