~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to core/windows/src/org/netbeans/core/windows/persistence/TCGroupParser.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
6
 * The contents of this file are subject to the terms of either the GNU
 
7
 * General Public License Version 2 only ("GPL") or the Common
 
8
 * Development and Distribution License("CDDL") (collectively, the
 
9
 * "License"). You may not use this file except in compliance with the
 
10
 * License. You can obtain a copy of the License at
 
11
 * http://www.netbeans.org/cddl-gplv2.html
 
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 
13
 * specific language governing permissions and limitations under the
 
14
 * License.  When distributing the software, include this License Header
 
15
 * Notice in each file and include the License file at
 
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 
17
 * particular file as subject to the "Classpath" exception as provided
 
18
 * by Sun in the GPL Version 2 section of the License file that
 
19
 * accompanied this code. If applicable, add the following below the
 
20
 * License Header, with the fields enclosed by brackets [] replaced by
 
21
 * your own identifying information:
 
22
 * "Portions Copyrighted [year] [name of copyright owner]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * The Original Software is NetBeans. The Initial Developer of the Original
 
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 
28
 * Microsystems, Inc. All Rights Reserved.
 
29
 *
 
30
 * If you wish your version of this file to be governed by only the CDDL
 
31
 * or only the GPL Version 2, indicate your decision by adding
 
32
 * "[Contributor] elects to include this software in this distribution
 
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 
34
 * single choice of license, a recipient has the option to distribute
 
35
 * your version of this file under either the CDDL, the GPL Version 2 or
 
36
 * to extend the choice of license to its licensees as provided above.
 
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 
38
 * Version 2 license, then the option applies only if the new code is
 
39
 * made subject to such option by the copyright holder.
 
40
 */
 
41
 
 
42
package org.netbeans.core.windows.persistence;
 
43
 
 
44
import java.util.logging.Level;
 
45
import org.netbeans.core.windows.Debug;
 
46
import org.openide.filesystems.FileLock;
 
47
import org.openide.filesystems.FileObject;
 
48
import org.openide.filesystems.FileUtil;
 
49
import org.openide.modules.SpecificationVersion;
 
50
import org.openide.util.NbBundle;
 
51
import org.xml.sax.*;
 
52
import org.xml.sax.helpers.DefaultHandler;
 
53
 
 
54
import java.io.*;
 
55
import java.util.logging.Logger;
 
56
 
 
57
/**
 
58
 * Handle loading/saving of TopComponent reference in Group configuration data.
 
59
 *
 
60
 * @author Marek Slama
 
61
 */
 
62
 
 
63
class TCGroupParser {
 
64
    
 
65
    public static final String INSTANCE_DTD_ID_2_0
 
66
    = "-//NetBeans//DTD Top Component in Group Properties 2.0//EN"; // NOI18N
 
67
    
 
68
    private static final boolean DEBUG = Debug.isLoggable(TCGroupParser.class);
 
69
    
 
70
    /** Unique id from file name */
 
71
    private String tc_id;
 
72
    
 
73
    /** Module parent folder */
 
74
    private FileObject moduleParentFolder;
 
75
    
 
76
    /** Local parent folder */
 
77
    private FileObject localParentFolder;
 
78
    
 
79
    private InternalConfig internalConfig;
 
80
    
 
81
    /** true if wstcgrp file is present in module folder */
 
82
    private boolean inModuleFolder;
 
83
    /** true if wstcgrp file is present in local folder */
 
84
    private boolean inLocalFolder;
 
85
    
 
86
    public TCGroupParser(String tc_id) {
 
87
        this.tc_id = tc_id;
 
88
    }
 
89
    
 
90
    /** Load tcgroup configuration. */
 
91
    TCGroupConfig load () throws IOException {
 
92
        if (DEBUG) Debug.log(TCGroupParser.class, "load ENTER" + " tcGrp:" + tc_id);
 
93
        TCGroupConfig tcGroupCfg = new TCGroupConfig();
 
94
        PropertyHandler propertyHandler = new PropertyHandler();
 
95
        InternalConfig internalCfg = getInternalConfig();
 
96
        internalCfg.clear();
 
97
        propertyHandler.readData(tcGroupCfg, internalCfg);
 
98
        if (DEBUG) Debug.log(TCGroupParser.class, "load LEAVE" + " tcGrp:" + tc_id);
 
99
        return tcGroupCfg;
 
100
    }
 
101
    
 
102
    /** Save tcGroup configuration. */
 
103
    void save (TCGroupConfig tcGroupCfg) throws IOException {
 
104
        if (DEBUG) Debug.log(TCGroupParser.class, "save ENTER" + " tcGrp:" + tc_id);
 
105
        
 
106
        PropertyHandler propertyHandler = new PropertyHandler();
 
107
        InternalConfig internalCfg = getInternalConfig();
 
108
        propertyHandler.writeData(tcGroupCfg, internalCfg);
 
109
        if (DEBUG) Debug.log(TCGroupParser.class, "save LEAVE" + " tcGrp:" + tc_id);
 
110
    }
 
111
    
 
112
    String getName () {
 
113
        return tc_id;
 
114
    }
 
115
    
 
116
    /** Getter for internal configuration data.
 
117
     * @return instance of internal configuration data
 
118
     */
 
119
    InternalConfig getInternalConfig () {
 
120
        if (internalConfig == null) {
 
121
            internalConfig = new InternalConfig();
 
122
        }
 
123
        return internalConfig;
 
124
    }
 
125
    
 
126
    boolean isInModuleFolder () {
 
127
        return inModuleFolder;
 
128
    }
 
129
    
 
130
    void setInModuleFolder (boolean inModuleFolder) {
 
131
        this.inModuleFolder = inModuleFolder;
 
132
    }
 
133
    
 
134
    boolean isInLocalFolder () {
 
135
        return inLocalFolder;
 
136
    }
 
137
    
 
138
    void setInLocalFolder (boolean inLocalFolder) {
 
139
        this.inLocalFolder = inLocalFolder;
 
140
    }
 
141
    
 
142
    void setModuleParentFolder (FileObject moduleParentFolder) {
 
143
        this.moduleParentFolder = moduleParentFolder;
 
144
    }
 
145
    
 
146
    void setLocalParentFolder (FileObject localParentFolder) {
 
147
        this.localParentFolder = localParentFolder;
 
148
    }
 
149
    
 
150
    void log (String s) {
 
151
        Debug.log(TCGroupParser.class, s);
 
152
    }
 
153
    
 
154
    private final class PropertyHandler extends DefaultHandler {
 
155
        
 
156
        /** tcRef manager configuration data */
 
157
        private TCGroupConfig tcGroupConfig = null;
 
158
        
 
159
        /** internal configuration data */
 
160
        private InternalConfig internalConfig = null;
 
161
        
 
162
        /** Lock to prevent mixing readData and writeData */
 
163
        private final Object RW_LOCK = new Object();
 
164
        
 
165
        public PropertyHandler () {
 
166
        }
 
167
        
 
168
        private FileObject getConfigFOInput () {
 
169
            FileObject tcGroupConfigFO;
 
170
            if (isInLocalFolder()) {
 
171
                //log("-- TCGroupParser.getConfigFOInput" + " looking for LOCAL");
 
172
                tcGroupConfigFO = localParentFolder.getFileObject
 
173
                (TCGroupParser.this.getName(), PersistenceManager.TCGROUP_EXT);
 
174
            } else if (isInModuleFolder()) {
 
175
                //log("-- TCGroupParser.getConfigFOInput" + " looking for MODULE");
 
176
                tcGroupConfigFO = moduleParentFolder.getFileObject
 
177
                (TCGroupParser.this.getName(), PersistenceManager.TCGROUP_EXT);
 
178
            } else {
 
179
                //XXX should not happen
 
180
                tcGroupConfigFO = null;
 
181
            }
 
182
            //log("-- TCGroupParser.getConfigFOInput" + " tcGroupConfigFO:" + tcGroupConfigFO);
 
183
            return tcGroupConfigFO;
 
184
        }
 
185
 
 
186
        private FileObject getConfigFOOutput () throws IOException {
 
187
            FileObject tcGroupConfigFO;
 
188
            tcGroupConfigFO = localParentFolder.getFileObject
 
189
            (TCGroupParser.this.getName(), PersistenceManager.TCGROUP_EXT);
 
190
            if (tcGroupConfigFO != null) {
 
191
                //log("-- TCGroupParser.getConfigFOOutput" + " tcGroupConfigFO LOCAL:" + tcGroupConfigFO);
 
192
                return tcGroupConfigFO;
 
193
            } else {
 
194
                StringBuffer buffer = new StringBuffer();
 
195
                buffer.append(TCGroupParser.this.getName());
 
196
                buffer.append('.');
 
197
                buffer.append(PersistenceManager.TCGROUP_EXT);
 
198
                //XXX should be improved localParentFolder can be null
 
199
                tcGroupConfigFO = FileUtil.createData(localParentFolder, buffer.toString());
 
200
                //log("-- TCGroupParser.getConfigFOOutput" + " LOCAL not found CREATE");
 
201
 
 
202
                return tcGroupConfigFO;
 
203
            }
 
204
        }
 
205
        /** 
 
206
         Reads tcRef configuration data from XML file. 
 
207
         Data are returned in output params.
 
208
         */
 
209
        void readData (TCGroupConfig tcGroupCfg, InternalConfig internalCfg)
 
210
        throws IOException {
 
211
            tcGroupConfig = tcGroupCfg;
 
212
            internalConfig = internalCfg;
 
213
            
 
214
            FileObject cfgFOInput = getConfigFOInput();
 
215
            if (cfgFOInput == null) {
 
216
                throw new FileNotFoundException("[WinSys] Missing TCGroup configuration file:" // NOI18N
 
217
                + TCGroupParser.this.getName());
 
218
            }
 
219
            InputStream is = null;
 
220
            try {
 
221
                synchronized (RW_LOCK) {
 
222
                    //DUMP BEGIN
 
223
                    /*InputStream is = cfgFOInput.getInputStream();
 
224
                    byte [] arr = new byte [is.available()];
 
225
                    is.read(arr);
 
226
                    log("DUMP TCGroup: " + TCGroupParser.this.getName());
 
227
                    String s = new String(arr);
 
228
                    log(s);*/
 
229
                    //DUMP END
 
230
                    is = cfgFOInput.getInputStream();
 
231
                    PersistenceManager.getDefault().getXMLParser(this).parse(new InputSource(is));
 
232
                }
 
233
            } catch (SAXException exc) {
 
234
                // Turn into annotated IOException
 
235
                String msg = NbBundle.getMessage(TCGroupParser.class,
 
236
                                                 "EXC_TCGroupParse", cfgFOInput);
 
237
 
 
238
                throw (IOException) new IOException(msg).initCause(exc);
 
239
            } finally {
 
240
                try {
 
241
                    if (is != null) {
 
242
                        is.close();
 
243
                    }
 
244
                } catch (IOException exc) {
 
245
                    Logger.getLogger(TCGroupParser.class.getName()).log(Level.WARNING, null, exc);
 
246
                }
 
247
            }
 
248
                        
 
249
            tcGroupCfg = tcGroupConfig;
 
250
            internalCfg = internalConfig;
 
251
            
 
252
            tcGroupConfig = null;
 
253
            internalConfig = null;
 
254
        }
 
255
        
 
256
        public void startElement (String nameSpace, String name, String qname, Attributes attrs) 
 
257
        throws SAXException {
 
258
            if ("tc-group".equals(qname)) { // NOI18N
 
259
                handleTCGroup(attrs);
 
260
            } else if (internalConfig.specVersion.compareTo(new SpecificationVersion("2.0")) == 0) { // NOI18N
 
261
                //Parse version 2.0
 
262
                if ("module".equals(qname)) { // NOI18N
 
263
                    handleModule(attrs);
 
264
                } else if ("tc-id".equals(qname)) { // NOI18N
 
265
                    handleTcId(attrs);
 
266
                } else if ("open-close-behavior".equals(qname)) { // NOI18N
 
267
                    handleOpenCloseBehavior(attrs);
 
268
                }
 
269
            } else {
 
270
                log("-- TCGroupParser.startElement PARSING OLD");
 
271
                //Parse version < 2.0
 
272
            }
 
273
        }
 
274
 
 
275
        public void error(SAXParseException ex) throws SAXException  {
 
276
            throw ex;
 
277
        }
 
278
 
 
279
        /** Reads element "tc-group" */
 
280
        private void handleTCGroup (Attributes attrs) {
 
281
            String version = attrs.getValue("version"); // NOI18N
 
282
            if (version != null) {
 
283
                internalConfig.specVersion = new SpecificationVersion(version);
 
284
            } else {
 
285
                PersistenceManager.LOG.log(Level.WARNING,
 
286
                "[WinSys.TCGroupParser.handleTCGroup]" // NOI18N
 
287
                + " Warning: Missing attribute \"version\" of element \"tc-group\"."); // NOI18N
 
288
                internalConfig.specVersion = new SpecificationVersion("2.0"); // NOI18N
 
289
            }
 
290
        }
 
291
        
 
292
        /** Reads element "module" and updates mode config content */
 
293
        private void handleModule (Attributes attrs) {
 
294
            String moduleCodeName = attrs.getValue("name"); // NOI18N
 
295
            //Parse code name
 
296
            internalConfig.moduleCodeNameBase = null;
 
297
            internalConfig.moduleCodeNameRelease = null;
 
298
            internalConfig.moduleSpecificationVersion = null;
 
299
            if (moduleCodeName != null) {
 
300
                int i = moduleCodeName.indexOf('/');
 
301
                if (i != -1) {
 
302
                    internalConfig.moduleCodeNameBase = moduleCodeName.substring(0, i);
 
303
                    internalConfig.moduleCodeNameRelease = moduleCodeName.substring(i + 1);
 
304
                    checkReleaseCode(internalConfig);
 
305
                } else {
 
306
                    internalConfig.moduleCodeNameBase = moduleCodeName;
 
307
                }
 
308
                internalConfig.moduleSpecificationVersion = attrs.getValue("spec"); // NOI18N
 
309
            }
 
310
        }
 
311
 
 
312
        /** Checks validity of <code>moduleCodeNameRelease</code> field. 
 
313
         * Helper method. */
 
314
        private void checkReleaseCode (InternalConfig internalConfig) {
 
315
            // #24844. Repair the wrongly saved "null" string
 
316
            // as release number.
 
317
            if("null".equals(internalConfig.moduleCodeNameRelease)) { // NOI18N
 
318
                Logger.getLogger(TCGroupParser.class.getName()).log(Level.WARNING, null,
 
319
                                  new IllegalStateException("Module release code was saved as null string" +
 
320
                                                            " for module " +
 
321
                                                            internalConfig.moduleCodeNameBase +
 
322
                                                            "! Repairing."));
 
323
                internalConfig.moduleCodeNameRelease = null;
 
324
            }
 
325
        }
 
326
        
 
327
        /** Reads element "tc-id" */
 
328
        private void handleTcId (Attributes attrs) throws SAXException {
 
329
            String tc_id = attrs.getValue("id"); // NOI18N
 
330
            if (tc_id != null) {
 
331
                tcGroupConfig.tc_id = tc_id;
 
332
                if (!tc_id.equals(TCGroupParser.this.getName())) {
 
333
                    PersistenceManager.LOG.log(Level.WARNING,
 
334
                    "[WinSys.TCGroupParser.handleTcId]" // NOI18N
 
335
                    + " Error: Value of attribute \"id\" of element \"tc-id\"" // NOI18N
 
336
                    + " and configuration file name must be the same."); // NOI18N
 
337
                    throw new SAXException("Invalid attribute value"); // NOI18N
 
338
                }
 
339
            } else {
 
340
                PersistenceManager.LOG.log(Level.WARNING,
 
341
                "[WinSys.TCGroupParser.handleTcId]" // NOI18N
 
342
                + " Error: Missing required attribute \"id\" of element \"tc-id\"."); // NOI18N
 
343
                throw new SAXException("Missing required attribute"); // NOI18N
 
344
            }
 
345
        }
 
346
        
 
347
        /** Reads element "open-close-behavior" */
 
348
        private void handleOpenCloseBehavior (Attributes attrs) throws SAXException {
 
349
            String open = attrs.getValue("open"); // NOI18N;
 
350
            if (open != null) {
 
351
                if ("true".equals(open)) { // NOI18N
 
352
                    tcGroupConfig.open = true;
 
353
                } else if ("false".equals(open)) { // NOI18N
 
354
                    tcGroupConfig.open = false;
 
355
                } else {
 
356
                    PersistenceManager.LOG.log(Level.WARNING,
 
357
                    "[WinSys.TCGroupParser.handleOpenCloseBehavior]" // NOI18N
 
358
                    + " Warning: Invalid value of attribute \"open\"" // NOI18N
 
359
                    + " of element \"open-close-behavior\"."); // NOI18N
 
360
                    tcGroupConfig.open = false;
 
361
                }
 
362
            } else {
 
363
                PersistenceManager.LOG.log(Level.WARNING,
 
364
                "[WinSys.TCGroupParser.handleOpenCloseBehavior]" // NOI18N
 
365
                + " Warning: Missing required attribute \"open\"" // NOI18N
 
366
                + " of element \"open-close-behavior\"."); // NOI18N
 
367
                tcGroupConfig.open = false;
 
368
            }
 
369
            
 
370
            String close = attrs.getValue("close"); // NOI18N;
 
371
            if (close != null) {
 
372
                if ("true".equals(close)) { // NOI18N
 
373
                    tcGroupConfig.close = true;
 
374
                } else if ("false".equals(close)) { // NOI18N
 
375
                    tcGroupConfig.close = false;
 
376
                } else {
 
377
                    PersistenceManager.LOG.log(Level.WARNING,
 
378
                    "[WinSys.TCGroupParser.handleOpenCloseBehavior]" // NOI18N
 
379
                    + " Warning: Invalid value of attribute \"close\"" // NOI18N
 
380
                    + " of element \"open-close-behavior\"."); // NOI18N
 
381
                    tcGroupConfig.close = false;
 
382
                }
 
383
            } else {
 
384
                PersistenceManager.LOG.log(Level.WARNING,
 
385
                "[WinSys.TCGroupParser.handleOpenCloseBehavior]" // NOI18N
 
386
                + " Warning: Missing required attribute \"close\"" // NOI18N
 
387
                + " of element \"open-close-behavior\"."); // NOI18N
 
388
                tcGroupConfig.close = false;
 
389
            }
 
390
            
 
391
            String wasOpened = attrs.getValue("was-opened"); // NOI18N;
 
392
            if (wasOpened != null) {
 
393
                if ("true".equals(wasOpened)) { // NOI18N
 
394
                    tcGroupConfig.wasOpened = true;
 
395
                } else if ("false".equals(wasOpened)) { // NOI18N
 
396
                    tcGroupConfig.wasOpened = false;
 
397
                } else {
 
398
                    PersistenceManager.LOG.log(Level.WARNING,
 
399
                    "[WinSys.TCGroupParser.handleOpenCloseBehavior]" // NOI18N
 
400
                    + " Warning: Invalid value of attribute \"was-opened\"" // NOI18N
 
401
                    + " of element \"open-close-behavior\"."); // NOI18N
 
402
                    tcGroupConfig.wasOpened = false;
 
403
                }
 
404
            } else {
 
405
                tcGroupConfig.wasOpened = false;
 
406
            }
 
407
        }
 
408
        
 
409
        /** Writes data from asociated tcRef to the xml representation */
 
410
        void writeData (TCGroupConfig tcGroupCfg, InternalConfig ic) throws IOException {
 
411
            final StringBuffer buff = fillBuffer(tcGroupCfg, ic);
 
412
            synchronized (RW_LOCK) {
 
413
                FileObject cfgFOOutput = getConfigFOOutput();
 
414
                FileLock lock = null;
 
415
                OutputStream os = null;
 
416
                OutputStreamWriter osw = null;
 
417
                try {
 
418
                    lock = cfgFOOutput.lock();
 
419
                    os = cfgFOOutput.getOutputStream(lock);
 
420
                    osw = new OutputStreamWriter(os, "UTF-8"); // NOI18N
 
421
                    osw.write(buff.toString());
 
422
                    //log("DUMP TCGroup: " + TCGroupParser.this.getName());
 
423
                    //log(buff.toString());
 
424
                } finally {
 
425
                    try {
 
426
                        if (osw != null) {
 
427
                            osw.close();
 
428
                        }
 
429
                    } catch (IOException exc) {
 
430
                        Logger.getLogger(TCGroupParser.class.getName()).log(Level.WARNING, null, exc);
 
431
                    }
 
432
                    if (lock != null) {
 
433
                        lock.releaseLock();
 
434
                    }
 
435
                }
 
436
            }
 
437
        }
 
438
        
 
439
        /** Returns xml content in StringBuffer
 
440
         */
 
441
        private StringBuffer fillBuffer (TCGroupConfig tcGroupCfg, InternalConfig ic) throws IOException {
 
442
            StringBuffer buff = new StringBuffer(800);
 
443
            String curValue = null;
 
444
            // header
 
445
            buff.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n"). // NOI18N
 
446
            /*buff.append("<!DOCTYPE tc-group PUBLIC\n"); // NOI18N
 
447
            buff.append("          \"-//NetBeans//DTD Top Component in Group Properties 2.0//EN\"\n"); // NOI18N
 
448
            buff.append("          \"http://www.netbeans.org/dtds/tc-group2_0.dtd\">\n\n"); // NOI18N*/
 
449
                append("<tc-group version=\"2.0\">\n"); // NOI18N
 
450
            
 
451
            appendModule(ic, buff);
 
452
            appendTcId(tcGroupCfg, buff);
 
453
            appendOpenCloseBehavior(tcGroupCfg, buff);
 
454
            
 
455
            buff.append("</tc-group>\n"); // NOI18N
 
456
            return buff;
 
457
        }
 
458
        
 
459
        private void appendModule (InternalConfig ic, StringBuffer buff) {
 
460
            if (ic == null) {
 
461
                return;
 
462
            }
 
463
            if (ic.moduleCodeNameBase != null) {
 
464
                buff.append(" <module name=\""); // NOI18N
 
465
                buff.append(ic.moduleCodeNameBase);
 
466
                if (ic.moduleCodeNameRelease != null) {
 
467
                    buff.append("/").append(ic.moduleCodeNameRelease); // NOI18N
 
468
                }
 
469
                if (ic.moduleSpecificationVersion != null) { 
 
470
                    buff.append("\" spec=\""); // NOI18N
 
471
                    buff.append(ic.moduleSpecificationVersion);
 
472
                }
 
473
                buff.append("\" />\n"); // NOI18N
 
474
            }
 
475
        }
 
476
 
 
477
        private void appendTcId (TCGroupConfig tcGroupCfg, StringBuffer buff) {
 
478
            buff.append(" <tc-id id=\"").append(
 
479
                    PersistenceManager.escapeTcId4XmlContent(tcGroupCfg.tc_id)).
 
480
                    append("\"/>\n"); // NOI18N
 
481
        }
 
482
        
 
483
        private void appendOpenCloseBehavior (TCGroupConfig tcGroupCfg, StringBuffer buff) {
 
484
            buff.append(" <open-close-behavior open=\"").append(tcGroupCfg.open). // NOI18N
 
485
                append("\" close=\"").append(tcGroupCfg.close). // NOI18N
 
486
                append("\" was-opened=\"").append(tcGroupCfg.wasOpened).append("\"/>\n"); // NOI18N
 
487
        }
 
488
        
 
489
    }
 
490
    
 
491
}