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:
042: package org.netbeans.modules.editor.options;
043:
044: import java.io.File;
045: import java.io.IOException;
046: import java.io.OutputStream;
047: import java.util.ArrayList;
048: import java.util.HashMap;
049: import java.util.Hashtable;
050: import java.util.Iterator;
051: import java.util.List;
052: import java.util.Map;
053: import org.netbeans.editor.Settings;
054:
055: import org.openide.cookies.InstanceCookie;
056: import org.openide.filesystems.FileChangeAdapter;
057: import org.openide.filesystems.FileEvent;
058: import org.openide.filesystems.FileLock;
059: import org.openide.filesystems.FileObject;
060: import org.openide.filesystems.FileStateInvalidException;
061: import org.openide.filesystems.FileSystem;
062: import org.openide.loaders.DataFolder;
063: import org.openide.loaders.DataObject;
064: import org.openide.loaders.FolderInstance;
065: import org.openide.util.TaskListener;
066: import org.openide.util.Task;
067: import org.openide.xml.XMLUtil;
068: import org.w3c.dom.Document;
069: import org.openide.loaders.DataObjectNotFoundException;
070: import java.lang.ClassNotFoundException;
071: import org.netbeans.editor.BaseKit;
072: import org.openide.loaders.DataObjectExistsException;
073: import java.lang.reflect.Field;
074: import org.openide.filesystems.Repository;
075:
076: /** MIME Options Folder representation.
077: * Folder maintains MIME specific settings.
078: * The folder contains XML settings files like fontscolors.xml,
079: * abbreviations.xml, macros.xml, properties.xml ...
080: * The folder also contains multi property subFolders like Popup, Macros, Abbreviations ...
081: *
082: * @author Martin Roskanin
083: * @since 08/2001
084: */
085:
086: public class MIMEOptionFolder {
087:
088: private Map files = new HashMap(5);
089: private BaseOptions base;
090: private DataFolder folder;
091: private Map mpFolderMap = new Hashtable();
092: private Map subFolders = new Hashtable();
093:
094: /** Creates new MIMEOptionFolder */
095: public MIMEOptionFolder(DataFolder f, BaseOptions bean) {
096: folder = f;
097:
098: /* commenting due to issue #65446
099: folder.getPrimaryFile().addFileChangeListener(new FileChangeAdapter(){
100: // update settings if new xml settings files appear
101: public void fileDataCreated(FileEvent fe) {
102: loadAllFiles();
103: }
104:
105: public void fileChanged(FileEvent fe) {
106: loadAllFiles();
107: }
108:
109: });
110: */
111:
112: base = bean;
113: loadAllFiles();
114: }
115:
116: /** Creates instance of all founded and recognized XML files */
117: protected Object createInstance(InstanceCookie[] cookies)
118: throws java.io.IOException, ClassNotFoundException {
119: for (int i = 0; i < cookies.length; i++) {
120: if (!(MIMEProcessor.class.isAssignableFrom(cookies[i]
121: .instanceClass()))) {
122: continue;
123: }
124:
125: MIMEProcessor mp = (MIMEProcessor) cookies[i]
126: .instanceCreate();
127: if (!files.containsKey(mp.instanceClass())) {
128: synchronized (Settings.class) {
129: files.put(mp.instanceClass(), mp
130: .createMIMEOptionFile(base, mp));
131: }
132: } else {
133: MIMEOptionFile mof = (MIMEOptionFile) files.get(mp
134: .instanceClass());
135: if (mof != null) {
136: mof.reloadSettings();
137: }
138: }
139: }
140:
141: return null;
142: }
143:
144: private void loadAllFiles() {
145: DataObject dob[] = folder.getChildren();
146: for (int i = 0; i < dob.length; i++) {
147: InstanceCookie ic = (InstanceCookie) dob[i]
148: .getCookie(InstanceCookie.class);
149: if (ic != null) {
150: InstanceCookie instanceCookie[] = new InstanceCookie[] { ic };
151: try {
152: createInstance(instanceCookie);
153: } catch (ClassNotFoundException cnfe) {
154: cnfe.printStackTrace();
155: } catch (IOException ioex) {
156: ioex.printStackTrace();
157: }
158: }
159: }
160: }
161:
162: /** Gets Multi Property Folder */
163: MultiPropertyFolder getMPFolder(String folderName,
164: boolean forceCreation) {
165: // check local map first
166: synchronized (Settings.class) {
167: MultiPropertyFolder mpFolder = (MultiPropertyFolder) mpFolderMap
168: .get(folderName);
169: if (mpFolder != null)
170: return mpFolder;
171: }
172:
173: FileObject fo = Repository.getDefault().getDefaultFileSystem()
174: .findResource(
175: folder.getPrimaryFile().getPath() + "/"
176: + folderName); //NOI18N
177:
178: if ((fo == null) && forceCreation) {
179: // let's create a DataFolder
180: try {
181: DataFolder.create(folder, folderName);
182: fo = Repository.getDefault().getDefaultFileSystem()
183: .findResource(
184: folder.getPrimaryFile().getPath() + "/"
185: + folderName); //NOI18N
186: } catch (IOException ioe) {
187: return null;
188: }
189: }
190:
191: if (fo == null)
192: return null;
193:
194: DataFolder df = DataFolder.findFolder(fo);
195: if (df != null) {
196: synchronized (Settings.class) {
197: MultiPropertyFolder mpFolder;
198: if (!mpFolderMap.containsKey(folderName)) {
199: mpFolder = new MultiPropertyFolder(df, base);
200: mpFolderMap.put(folderName, mpFolder);
201: } else {
202: mpFolder = (MultiPropertyFolder) mpFolderMap
203: .get(folderName);
204: }
205: return mpFolder;
206: }
207: }
208:
209: return null;
210: }
211:
212: /** Gets Multi Property folder properties
213: * @param folderName the name of multi property subFolder */
214: List getFolderProperties(String folderName) {
215: MultiPropertyFolder mpFolder = getMPFolder(folderName, false);
216: return (mpFolder != null) ? mpFolder.getProperties()
217: : new ArrayList();
218: }
219:
220: /** Sets Multi Property folder properties
221: * @param folderName the name of multi property subFolder
222: * @param props List of new properties values */
223: void setFolderProperties(String folderName, List props) {
224: MultiPropertyFolder mpFolder = getMPFolder(folderName, true);
225: if (mpFolder != null) {
226: mpFolder.setProperties(props);
227: }
228: }
229:
230: /** Gets the data folder of this MIMEOptionFolder */
231: protected DataFolder getDataFolder() {
232: return folder;
233: }
234:
235: /** Gets MIME Option subFolder from this folder
236: * @param subFolder the name of subFolder */
237: protected MIMEOptionFolder getFolder(String subFolder) {
238:
239: synchronized (Settings.class) {
240: if (subFolders.get(subFolder) != null) {
241: return (MIMEOptionFolder) subFolders.get(subFolder);
242: }
243:
244: org.openide.filesystems.FileObject f = Repository
245: .getDefault().getDefaultFileSystem().findResource(
246: folder.getPrimaryFile().getPath() + "/"
247: + subFolder); // NOI18N
248: if (f == null)
249: return null;
250:
251: try {
252: DataObject d = DataObject.find(f);
253: DataFolder df = (DataFolder) d
254: .getCookie(DataFolder.class);
255: if (df != null) {
256: MIMEOptionFolder mof = new MIMEOptionFolder(df,
257: base);
258: subFolders.put(subFolder, mof);
259: return mof;
260: }
261: } catch (org.openide.loaders.DataObjectNotFoundException ex) {
262: ex.printStackTrace();
263: }
264:
265: return null;
266: }
267: }
268:
269: /** Gets MIME specific file located in this folder
270: * @param file Processor file class
271: * @param forceCreation if true, empty XML file will be created
272: * (used for saving the file ). False is used for loading file. */
273: protected MIMEOptionFile getFile(Class file, boolean forceCreation) {
274:
275: if (forceCreation && (!files.containsKey(file))) {
276: String publicID = null;
277: String systemID = null;
278: String tagRoot = null;
279: String fn = null;
280:
281: if (FontsColorsMIMEProcessor.class.isAssignableFrom(file)) {
282: publicID = FontsColorsMIMEProcessor.PUBLIC_ID;
283: systemID = FontsColorsMIMEProcessor.SYSTEM_ID;
284: tagRoot = FontsColorsMIMEOptionFile.TAG_ROOT;
285: fn = FontsColorsMIMEOptionFile.FILENAME;
286: }
287:
288: else if (AbbrevsMIMEProcessor.class.isAssignableFrom(file)) {
289: publicID = AbbrevsMIMEProcessor.PUBLIC_ID;
290: systemID = AbbrevsMIMEProcessor.SYSTEM_ID;
291: tagRoot = AbbrevsMIMEOptionFile.TAG_ROOT;
292: fn = AbbrevsMIMEOptionFile.FILENAME;
293: }
294:
295: else if (MacrosMIMEProcessor.class.isAssignableFrom(file)) {
296: publicID = MacrosMIMEProcessor.PUBLIC_ID;
297: systemID = MacrosMIMEProcessor.SYSTEM_ID;
298: tagRoot = MacrosMIMEOptionFile.TAG_ROOT;
299: fn = MacrosMIMEOptionFile.FILENAME;
300: }
301:
302: else if (KeyBindingsMIMEProcessor.class
303: .isAssignableFrom(file)) {
304: publicID = KeyBindingsMIMEProcessor.PUBLIC_ID;
305: systemID = KeyBindingsMIMEProcessor.SYSTEM_ID;
306: tagRoot = KeyBindingsMIMEOptionFile.TAG_ROOT;
307: fn = KeyBindingsMIMEOptionFile.FILENAME;
308: }
309:
310: else if (PropertiesMIMEProcessor.class
311: .isAssignableFrom(file)) {
312: publicID = PropertiesMIMEProcessor.PUBLIC_ID;
313: systemID = PropertiesMIMEProcessor.SYSTEM_ID;
314: tagRoot = PropertiesMIMEOptionFile.TAG_ROOT;
315: fn = PropertiesMIMEOptionFile.FILENAME;
316: }
317:
318: else {
319: // providing possibility for other MIMEProcessor types
320: Object inst = null;
321:
322: try {
323: inst = file.newInstance();
324: } catch (InstantiationException ie) {
325: return null;
326: } catch (IllegalAccessException iae) {
327: return null;
328: }
329:
330: // Get rid of unknown processors
331: if (!(inst instanceof MIMEProcessor))
332: return null;
333:
334: MIMEProcessor processorInst = (MIMEProcessor) inst;
335:
336: publicID = processorInst.getPublicID();
337: systemID = processorInst.getSystemID();
338:
339: Class mofClass = processorInst
340: .getAsociatedMIMEOptionFile();
341:
342: try {
343: Field tagRootField = mofClass
344: .getDeclaredField("TAG_ROOT"); //NOI18N
345: if (tagRootField != null) {
346: Object objFld = tagRootField.get(mofClass);
347: if ((objFld != null)
348: && (objFld instanceof String)) {
349: tagRoot = (String) objFld;
350: }
351: }
352:
353: Field fnField = mofClass
354: .getDeclaredField("FILENAME"); //NOI18N
355: if (fnField != null) {
356: Object objFld = fnField.get(mofClass);
357: if ((objFld != null)
358: && (objFld instanceof String)) {
359: fn = (String) objFld;
360: }
361: }
362: } catch (Exception exc) {
363: return null;
364: }
365:
366: }
367:
368: if (publicID == null || systemID == null || tagRoot == null
369: || fn == null)
370: return null;
371:
372: synchronized (Settings.class) {
373: createEmptyXMLFile(fn, tagRoot, publicID, systemID);
374: }
375: }
376: return (MIMEOptionFile) files.get(file);
377: }
378:
379: /** Creates empty XML file with given name, root tag, publis ID and system ID */
380: private void createEmptyXMLFile(String fileName, String tagRoot,
381: String publicID, String systemID) {
382:
383: final String fn = fileName;
384:
385: final Document doc = XMLUtil.createDocument(tagRoot, null,
386: publicID, systemID);
387:
388: try {
389: final FileObject[] fileObj = new FileObject[1];
390: folder.getPrimaryFile().getFileSystem().runAtomicAction(
391: new FileSystem.AtomicAction() {
392: public void run() throws IOException {
393: if (folder.getPrimaryFile().getFileObject(
394: fn, "xml") != null)
395: return; //NOI18N
396: // file doesn't exist, create it.
397: fileObj[0] = folder.getPrimaryFile()
398: .createData(fn, "xml"); // NOI18N
399: FileLock lock = fileObj[0].lock();
400: try {
401: OutputStream os = fileObj[0]
402: .getOutputStream(lock);
403: try {
404: XMLUtil.write(doc, os, "UTF-8"); // NOI18N
405: os.flush();
406: } finally {
407: os.close();
408: }
409: } finally {
410: lock.releaseLock();
411: }
412: }
413: });
414:
415: if (fileObj[0] == null)
416: return;
417:
418: try {
419: DataObject dobj = DataObject.find(fileObj[0]);
420: if (dobj != null) {
421: InstanceCookie ic = (InstanceCookie) dobj
422: .getCookie(InstanceCookie.class);
423: if (ic != null) {
424: InstanceCookie instanceCookie[] = new InstanceCookie[] { ic };
425: try {
426: createInstance(instanceCookie);
427: } catch (ClassNotFoundException cnfe) {
428: cnfe.printStackTrace();
429: } catch (IOException ioex) {
430: ioex.printStackTrace();
431: }
432: }
433: }
434: } catch (DataObjectNotFoundException donf) {
435: donf.printStackTrace();
436: }
437:
438: } catch (FileStateInvalidException fsie) {
439: fsie.printStackTrace();
440: } catch (IOException ioe) {
441: ioe.printStackTrace();
442: }
443: }
444:
445: }
|